#pragma
#include <iostream>
#include <memory>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"

//#include "Listener.hpp"




class Reactor{
private:
    static const int reves_num = 128;
    bool IsConnectionEmpty()//判断映射数组是否为空
    {
        return _connections.empty();
    }

    int LoopOnce(int timeout)//等待文件描述符就绪
    {
        return _epoll_ptr->WaitEvents(_revs, reves_num, timeout);
    }

    bool IsConnectionExistsHelper(int sockfd)
    {
        auto iter = _connections.find(sockfd);//按照key值查找
        if(iter == _connections.end())
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    bool IsConnectionExists(int sockfd)
    {
        return IsConnectionExistsHelper(sockfd);
    }

    bool IsConnectionExists(std::shared_ptr<Connection>& conn)
    {
        return IsConnectionExistsHelper(conn->GetSockFd());
    }
    void Dispatcher(int num)//事件派发器
    {
        
        for(int i = 0; i < num; i++)
        {
           int sockfd = _revs[i].data.fd;//获取就绪文件描述符
           uint32_t event = _revs[i].events;//获取就绪文件描述符所关心的时间
           
           //将一切异常处理转换成I/O错误,所有的I/O错误转换成一个异常处理函数
           if(event & EPOLLERR)//epoll发生致命的错误
                event |= EPOLLIN | EPOLLOUT;
           if(event & EPOLLHUP)//对端关闭连接
            {
                event |= EPOLLIN | EPOLLOUT; 
            }


           if(event & EPOLLIN)//读事件就绪
           {
                //std::cout << "sockfd" << std::endl;
                if(IsConnectionExists(sockfd))
                {
                    //std::cout << "进入" << sockfd << std::endl;
                    _connections[sockfd]->Recver();//利用多态的思想调用各自的发送方法
                }
           }
           if(event & EPOLLOUT)//写事件就绪
           {
                if(IsConnectionExists(sockfd))
                {
                    _connections[sockfd]->Sender();
                }
           }
        }
    }
public:
    Reactor()
    :_epoll_ptr(std::make_unique<Epoller>()),//初始化epoll对象
     _isruning(false)
    {
        
    }

    void Loop()//容器入口函数
    {
        if(IsConnectionEmpty())//如果映射关系为空说明没有文件描述符添加进来
        {
            return;
        }
        _isruning = true;
        int timeout = -1;//阻塞等待,直到有文件描述符就绪才被唤醒
        while(_isruning)
        {
            PrintFd();
            int n = LoopOnce(timeout);
            //std::cout << n << std::endl;
            Dispatcher(n);//将就绪文件描述符交给事件派发器
        }
        _isruning = false;
    }

    void AddConnection(std::shared_ptr<Connection>& conn)//将连接对象中的文件描述符及信息添加到内核
    {

        if(IsConnectionExists(conn))//看一下文件描述符是否已经存在
        {
            //已经存在
            LOG(LogLevel::WARNING) << "conn is exists";
            return;
        }
        //不存在,添加进来
        uint32_t event = conn->GetEvent();//获取关心事件
        int fd = conn->GetSockFd();//获取文件描述符

        _epoll_ptr->AddEvent(event, fd);//将信息添加入内核

        _connections[fd] = conn;//添加映射关系

        conn->SetOwner(this);//设置文件描述符管理对象的回调指针
    }

    void EnableReadWrite(int sockfd, bool enableread, bool enablewrite)
    {
        if(!IsConnectionExists(sockfd))
        {
            LOG(LogLevel::WARNING) << "EnableReadWrite, conn is exists: " << sockfd;
            return;
        }

        //修改当前sockfd的关心事件
        uint32_t new_event = (EPOLLET | (enableread ? EPOLLIN : 0) | (enablewrite ? EPOLLOUT : 0));
        _connections[sockfd]->SetEvent(new_event);

        //将修改的内容写入内核
        _epoll_ptr->ModEvent(sockfd,new_event);
    }

    void DelConnection(int sockfd)
    {
        //从内核中移除的文件描述符要是合法的
        _epoll_ptr->DelEvent(sockfd);

        //从_connections中删除fd，删除时会自动调用析构函数
        _connections.erase(sockfd);

        //关闭不存在的fd
        close(sockfd);

        LOG(LogLevel::INFO) << "client quit: " << sockfd;
    }
    void Stop()//容器停止函数
    {
        _isruning = false;
    }

    void PrintFd()
    {
        for(auto& conn : _connections)
        {
            std::cout << "fd: " << conn.second->GetSockFd() << " ";
        }
        std::cout << "\r\n";
    }
    ~Reactor()
    {

    }
private:
    std::unique_ptr<Epoller> _epoll_ptr;//epoll模型

    std::unordered_map<int, std::shared_ptr<Connection>> _connections;//文件描述符和和文件描述符对象的映射关系
    //std::unique_ptr<Channel> _channel;//我的想法错误

    bool _isruning;

    struct epoll_event _revs[reves_num];//用来存储已经就绪的文件描述符
    
};